package de.g18.gruppe3.ldapinterface.service;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import de.g18.gruppe3.common.exception.NotPersistentLDAPModelException;
import de.g18.gruppe3.common.exception.UserGroupNotFoundExeption;
import de.g18.gruppe3.common.exception.UserToUserGroupAssignmentFailException;
import de.g18.gruppe3.common.ldap.UserGroupService;
import de.g18.gruppe3.common.model.User;
import de.g18.gruppe3.common.model.UserGroup;

/**
 * Implementierung des {@link UserGroupService}
 *
 * @author <a href="mailto:kevinhuber.kh@gmail.com">Kevin Huber</a>
 */
public class UserGroupServiceImpl implements UserGroupService {

    private static final LDAPContext LDAP = LDAPContext.getInstance();


    @Override
    public UserGroup getUserGroupByName(String aName) throws UserGroupNotFoundExeption {
        SearchControls controlls = new SearchControls();
        String[] resultAttributes = {"cn"};
        controlls.setReturningAttributes(resultAttributes);
        controlls.setSearchScope(SearchControls.ONELEVEL_SCOPE);

        String filter = "(&(objectClass=group)(cn=" + aName + "))";
        try {
            NamingEnumeration<SearchResult> resultList =
                LDAP.search(LDAPContext.DOMAIN_ROOT, filter, controlls);

            if (!resultList.hasMore()) {
                throw new UserGroupNotFoundExeption(aName);
            }
            SearchResult result = resultList.next();
            Attributes attributes = result.getAttributes();

            UserGroup group = new UserGroup((String) attributes.get("cn").get());
            group.setDistinguishedName(generateUserGroupDN(group));
            group.setPersisted(true);
            return group;
        } catch (NamingException e) {
            throw new IllegalStateException("Gruppe konnte nicht geladen werden!", e);
        }
    }

    private String generateUserGroupDN(UserGroup aUserGroup) {
        return "cn=" + aUserGroup.getName() + "," + LDAPContext.DOMAIN_ROOT;
    }

    @Override
    public void addUserToUserGroup(User aUserToAdd, UserGroup aUserGroup) throws UserToUserGroupAssignmentFailException, NotPersistentLDAPModelException {
        if (!aUserToAdd.isPersisted()) {
            throw new NotPersistentLDAPModelException(User.class);
        }
        if (!aUserGroup.isPersisted()) {
            throw new NotPersistentLDAPModelException(UserGroup.class);
        }

        try {
            ModificationItem[] mods = new ModificationItem[1];

            Attribute mod = new BasicAttribute("member", aUserToAdd.getDistinguishedName());
            mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod);
            LDAP.modifyAttributes(aUserGroup.getDistinguishedName(), mods);
        } catch (NamingException e) {
            throw new UserToUserGroupAssignmentFailException(aUserGroup.getName(), aUserGroup.getName(), e);
        }
    }
}
